Let us set some global options for all code chunks in this document.

# Set seed for reproducibility
set.seed(1982) 
# Set global options for all code chunks
knitr::opts_chunk$set(
  # Disable messages printed by R code chunks
  message = FALSE,    
  # Disable warnings printed by R code chunks
  warning = FALSE,    
  # Show R code within code chunks in output
  echo = TRUE,        
  # Include both R code and its results in output
  include = TRUE,     
  # Evaluate R code chunks
  eval = TRUE,       
  # Enable caching of R code chunks for faster rendering
  cache = FALSE,      
  # Align figures in the center of the output
  fig.align = "center",
  # Enable retina display for high-resolution figures
  retina = 2,
  # Show errors in the output instead of stopping rendering
  error = TRUE,
  # Do not collapse code and output into a single block
  collapse = FALSE
)
# Start the figure counter
fig_count <- 0
# Define the captioner function
captioner <- function(caption) {
  fig_count <<- fig_count + 1
  paste0("Figure ", fig_count, ": ", caption)
}
# Define the function to truncate a number to two decimal places
truncate_to_two <- function(x) {
  floor(x * 100) / 100
}
# inla.upgrade(testing = TRUE)
# remotes::install_github("inlabru-org/inlabru", ref = "devel")
# remotes::install_github("davidbolin/rspde", ref = "devel")
# remotes::install_github("davidbolin/metricgraph", ref = "devel")
library(INLA)
library(inlabru)
library(rSPDE)
library(MetricGraph)
library(grateful)

library(plotly)

We want to solve the fractional diffusion equation \[\begin{equation} \label{eq:maineq} \partial_t u+(\kappa^2-\Delta_\Gamma)^{\frac{\alpha}{2}} u=f \text { on } \Gamma \times(0, T), \quad u(0)=u_0 \text { on } \Gamma, \end{equation}\] where \(u\) satisfies the Kirchhoff vertex conditions \[\begin{equation} \label{eq:Kcond} \left\{\phi\in C(\Gamma)\;\Big|\; \forall v\in V: \sum_{e\in\mathcal{E}_v}\partial_e \phi(v)=0 \right\} \end{equation}\]

If \(f=0\), then the solution is given by \[\begin{equation} \label{eq:sol_reprentation} u(s,t) = \displaystyle\sum_{j\in\mathbb{N}}e^{-\lambda^{\frac{\alpha}{2}}_jt}\left(u_0, e_j\right)_{L_2(\Gamma)}e_j(s). \end{equation}\]

# Function to build a tadpole graph and create a mesh
gets_graph_tadpole <- function(h){
  edge1 <- rbind(c(0,0),c(1,0))
  theta <- seq(from=-pi,to=pi,length.out = 100)
  edge2 <- cbind(1+1/pi+cos(theta)/pi,sin(theta)/pi)
  edges = list(edge1, edge2)
  graph <- metric_graph$new(edges = edges)
  graph$build_mesh(h = h)
  return(graph)
}

Let \(\Gamma_T = (\mathcal{V},\mathcal{E})\) characterize the tadpole graph with \(\mathcal{V}= \{v_1,v_2\}\) and \(\mathcal{E}= \{e_1,e_2\}\) as specified in Figure \(\ref{Interval.Circle.Tadpole}\)c. The left edge \(e_1\) has length 1 and the circular edge \(e_2\) has length 2. As discussed in Subsection \(\ref{subsec:prelim}\), a point on \(e_1\) is parameterized via \(s=\left(e_1, t\right)\) for \(t \in[0,1]\) and a point on \(e_2\) via \(s=\left(e_2, t\right)\) for \(t\in[0,2]\). One can verify that \(-\Delta_\Gamma\) has eigenvalues \(0,\left\{(i \pi / 2)^2\right\}_{i \in \mathbb{N}}\) and \(\left\{(i \pi / 2)^2\right\}_{2 i \in \mathbb{N}}\) with corresponding eigenfunctions \(\phi_0\), \(\left\{\phi_i\right\}_{i \in \mathbb{N}}\), and \(\left\{\psi_i\right\}_{2 i \in \mathbb{N}}\) given by \(\phi_0(s)=1 / \sqrt{3}\) and \[\begin{equation*} \phi_i(s)=C_{\phi, i}\begin{cases} -2 \sin (\frac{i\pi}{2}) \cos (\frac{i \pi t}{2}), & s \in e_1, \\ \sin (i \pi t / 2), & s \in e_2, \end{cases}, \quad \psi_i(s)=\frac{\sqrt{3}}{\sqrt{2}} \begin{cases} (-1)^{i / 2} \cos (\frac{i \pi t}{2}), & s \in e_1, \\ \cos (\frac{i \pi t}{2}), & s \in e_2, \end{cases}, \end{equation*}\] where \(C_{\phi, i}=1\) if \(i\) is even and \(C_{\phi, i}=1 / \sqrt{3}\) otherwise. Moreover, these functions form an orthonormal basis for \(L_2(\Gamma_T)\).

# Function to compute the eigenfunctions 
tadpole.eig <- function(k,graph){
x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 

if(k==0){ 
  f.e1 <- rep(1,length(x1)) 
  f.e2 <- rep(1,length(x2)) 
  f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
  f = list(phi=f1/sqrt(3)) 
  
} else {
  f.e1 <- -2*sin(pi*k*1/2)*cos(pi*k*x1/2) 
  f.e2 <- sin(pi*k*x2/2)                  
  
  f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
  
  if((k %% 2)==1){ 
    f = list(phi=f1/sqrt(3)) 
  } else { 
    f.e1 <- (-1)^{k/2}*cos(pi*k*x1/2)
    f.e2 <- cos(pi*k*x2/2)
    f2 = c(f.e1[1],f.e2[1],f.e1[-1],f.e2[-1]) 
    f <- list(phi=f1,psi=f2/sqrt(3/2))
  }
}

return(f)
}

Implementation of \(u\)

h <- 0.001
graph <- gets_graph_tadpole(h = h)
T_final <- 0.5
time_step <- 0.01
time_seq <- seq(0, T_final, by = time_step)
# Compute the FEM matrices
graph$compute_fem()
G <- graph$mesh$G
C <- graph$mesh$C
I <- Matrix::Diagonal(nrow(C))
x <- graph$mesh$V[, 1]
y <- graph$mesh$V[, 2]
edge_number <- graph$mesh$VtE[, 1]
pos <- sum(edge_number == 1)+1
order_to_plot <- function(v)return(c(v[1], v[3:pos], v[2], v[(pos+1):length(v)], v[2]))
weights <- graph$mesh$weights
# Initial condition
U_0 <- 10*exp(-((x-1)^2 + (y)^2))

U_true <- matrix(NA, nrow = nrow(C), ncol = length(time_seq))
U_true[, 1] <- U_0
kappa <- 1
alpha <- 1.3
beta <- alpha/2
L <- kappa^2*C + G
op <- fractional.operators(L, beta, C, scale.factor = kappa^2, m = 2)
Pl <- op$Pl
Pr <- op$Pr
Ci <- op$Ci
n_finite <- 100


for (k in 1:(length(time_seq) - 1)) {
  aux_k <- rep(0, nrow(C))
  for (j in 0:n_finite) {
    decay_j <- exp(-time_seq[k+1]*(kappa^2 + (j*pi/2)^2)^(alpha/2))
    e_j <- tadpole.eig(j,graph)$phi
    aux_k <- aux_k + decay_j*sum(U_0*e_j*weights)*e_j
    if (j>0 && (j %% 2 == 0)) {
      e_j <- tadpole.eig(j,graph)$psi
      aux_k <- aux_k + decay_j*sum(U_0*e_j*weights)*e_j
      }
    }
  U_true[, k + 1] <- aux_k
}
# Precompute the LHS1 matrix
LHS1 <- Pr + time_step * solve(C, Pl)
# Precompute the LHS2 matrix
aux <- Pr %*% solve(Pl, C)
LHS2 <- aux + time_step * Matrix::Diagonal(nrow(C)) 



# Initialize U matrix to store solution at each time step
U_approx1 <- matrix(NA, nrow = nrow(C), ncol = length(time_seq))
U_approx1[, 1] <- U_0

U_approx2 <- matrix(NA, nrow = nrow(C), ncol = length(time_seq))
U_approx2[, 1] <- U_0

# Time-stepping loop
for (k in 1:(length(time_seq) - 1)) {
  # Compute the right-hand side for the first equation
  RHS1 <- Pr %*% U_approx1[, k]
  U_approx1[, k + 1] <- as.matrix(solve(LHS1, RHS1))
  # Compute the right-hand side for the second equation
  RHS2 <- aux %*% U_approx2[, k]
  U_approx2[, k + 1] <- as.matrix(solve(LHS2, RHS2))
}
x <- order_to_plot(x)
y <- order_to_plot(y)
max_error_at_each_time1 <- apply(abs(U_true - U_approx1), 2, max)
max_error_at_each_time2 <- apply(abs(U_true - U_approx2), 2, max)
max_error_between_both_approx <- apply(abs(U_approx1 - U_approx2), 2, max)

U_true <- apply(U_true, 2, order_to_plot)
U_approx1 <- apply(U_approx1, 2, order_to_plot)
U_approx2 <- apply(U_approx2, 2, order_to_plot)

# Create interactive plot
fig <- plot_ly()

# Add first line (max_error_at_each_time1)
fig <- fig %>% add_trace(
  x = ~time_seq, y = ~max_error_at_each_time1, type = 'scatter', mode = 'lines+markers',
  line = list(color = 'red', width = 2),
  marker = list(size = 4),
  name = "Max Error Between True and Approx 1: (P_r +tau C^{-1}P_l)U^{k+1} = P_r U^{k}"
)

# Add second line (max_error_at_each_time2)
fig <- fig %>% add_trace(
  x = ~time_seq, y = ~max_error_at_each_time2, type = 'scatter', mode = 'lines+markers',
  line = list(color = 'blue', width = 2, dash = 'dash'),
  marker = list(size = 4),
  name = "Max Error Between True and Approx 2: (P_rP_l^{-1}C +tau I)U^{k+1} = P_rP_l^{-1}C U^{k}"
)

# Add third line (max_error_between_both_approx)

fig <- fig %>% add_trace(
  x = ~time_seq, y = ~max_error_between_both_approx, type = 'scatter', mode = 'lines+markers',
  line = list(color = 'green', width = 2, dash = 'dot'),
  marker = list(size = 4),
  name = "Max Error Between Approximations"
)

# Layout
fig <- fig %>% layout(
  title = "Max Error at Each Time Step",
  xaxis = list(title = "Time"),
  yaxis = list(title = "Max Error"),
  legend = list(x = 0.1, y = 0.9)
)


plot_data <- data.frame(
  x = rep(x, times = ncol(U_true)),
  y = rep(y, times = ncol(U_true)),
  z_true = as.vector(U_true),
  z_approx1 = as.vector(U_approx1),
  z_approx2 = as.vector(U_approx2),
  frame = rep(time_seq, each = length(x))
)

# Compute axis limits
x_range <- range(x)
y_range <- range(y)
z_range <- range(c(U_true, U_approx1, U_approx2))

# Initial plot setup (first frame only)
p <- plot_ly(plot_data, frame = ~frame) %>%
  add_trace(
    x = ~x, y = ~y, z = ~z_true,
    type = "scatter3d", mode = "lines",
    name = "True",
    line = list(color = "blue", width = 2)
  ) %>%
  add_trace(
    x = ~x, y = ~y, z = ~z_approx1,
    type = "scatter3d", mode = "lines",
    name = "Approx 1: (P_r +tau C^{-1}P_l)U^{k+1} = P_r U^{k}",
    line = list(color = "red", width = 2)
  ) %>%
  add_trace(
    x = ~x, y = ~y, z = ~z_approx2,
    type = "scatter3d", mode = "lines",
    name = "Approx 2: (P_rP_l^{-1}C +tau I)U^{k+1} = P_rP_l^{-1}C U^{k}",
    line = list(color = "green", width = 2)
  ) %>%
  layout(
    scene = list(
      xaxis = list(title = "x", range = x_range),
      yaxis = list(title = "y", range = y_range),
      zaxis = list(title = "Value", range = z_range)
    ),
    updatemenus = list(
      list(
        type = "buttons", showactive = FALSE,
        buttons = list(
          list(label = "Play", method = "animate",
               args = list(NULL, list(frame = list(duration = 100, redraw = TRUE), fromcurrent = TRUE))),
          list(label = "Pause", method = "animate",
               args = list(NULL, list(mode = "immediate", frame = list(duration = 0), redraw = FALSE)))
        )
      )
    ),
    title = "Time: 0"
  )

# Convert to plotly object with frame info
pb <- plotly_build(p)

# Inject custom titles into each frame
for (i in seq_along(pb$x$frames)) {
  t <- time_seq[i]
  err <- signif(max_error_between_both_approx[i], 4)
  pb$x$frames[[i]]$layout <- list(title = paste0("Time: ", t, " | Max Error: ", err))
}
fig  # Display the plot

Figure 1: Caption

pb

Figure 2: Caption

LS0tCnRpdGxlOiAiU29sdmluZyBhIHBhcmFib2xpYyBlcXVhdGlvbiIKZGF0ZTogIkNyZWF0ZWQ6IDIwLTA0LTIwMjUuIExhc3QgbW9kaWZpZWQ6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVkuJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG1hdGhqYXg6ICJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL21hdGhqYXhAMy9lczUvdGV4LW1tbC1jaHRtbC5qcyIKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZm9sZGluZzogc2hvdyAjIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiIHRvIGhpZGUgY29kZSBhbmQgYWRkIGEgYnV0dG9uIHRvIHNob3cgaXQKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQpiaWJsaW9ncmFwaHk6IAogIC0gcmVmZXJlbmNlcy5iaWIKICAtIGdyYXRlZnVsLXJlZnMuYmliCmhlYWRlci1pbmNsdWRlczoKICAtIFxuZXdjb21tYW5ke1xhcn17XG1hdGhiYntSfX0KICAtIFxuZXdjb21tYW5ke1xsbGF2fVsxXXtcbGVmdFx7IzFccmlnaHRcfX0KICAtIFxuZXdjb21tYW5ke1xwYXJlfVsxXXtcbGVmdCgjMVxyaWdodCl9CiAgLSBcbmV3Y29tbWFuZHtcTmNhbH17XG1hdGhjYWx7Tn19CiAgLSBcbmV3Y29tbWFuZHtcVmNhbH17XG1hdGhjYWx7Vn19CiAgLSBcbmV3Y29tbWFuZHtcRWNhbH17XG1hdGhjYWx7RX19CiAgLSBcbmV3Y29tbWFuZHtcV2NhbH17XG1hdGhjYWx7V319Ci0tLQoKYGBge3IgeGFyaW5nYW5FeHRyYS1jbGlwYm9hcmQsIGVjaG8gPSBGQUxTRX0KaHRtbHRvb2xzOjp0YWdMaXN0KAogIHhhcmluZ2FuRXh0cmE6OnVzZV9jbGlwYm9hcmQoCiAgICBidXR0b25fdGV4dCA9ICI8aSBjbGFzcz1cImZhLXNvbGlkIGZhLWNsaXBib2FyZFwiIHN0eWxlPVwiY29sb3I6ICMwMDAwOEJcIj48L2k+IiwKICAgIHN1Y2Nlc3NfdGV4dCA9ICI8aSBjbGFzcz1cImZhIGZhLWNoZWNrXCIgc3R5bGU9XCJjb2xvcjogIzkwQkU2RFwiPjwvaT4iLAogICAgZXJyb3JfdGV4dCA9ICI8aSBjbGFzcz1cImZhIGZhLXRpbWVzLWNpcmNsZVwiIHN0eWxlPVwiY29sb3I6ICNGOTQxNDRcIj48L2k+IgogICksCiAgcm1hcmtkb3duOjpodG1sX2RlcGVuZGVuY3lfZm9udF9hd2Vzb21lKCkKKQpgYGAKCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmJvZHkgLm1haW4tY29udGFpbmVyIHsKICBtYXgtd2lkdGg6IDEwMCUgIWltcG9ydGFudDsKICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Owp9CmJvZHkgewogIG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50Owp9Cgpib2R5LCB0ZCB7CiAgIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNHB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNHB4Cn0KLmN1c3RvbS1ib3ggewogIGJhY2tncm91bmQtY29sb3I6ICNmNWY3ZmE7IC8qIExpZ2h0IGdyZXktYmx1ZSBiYWNrZ3JvdW5kICovCiAgYm9yZGVyLWNvbG9yOiAjZTFlOGVkOyAvKiBMaWdodCBib3JkZXIgY29sb3IgKi8KICBjb2xvcjogIzJjM2U1MDsgLyogRGFyayB0ZXh0IGNvbG9yICovCiAgcGFkZGluZzogMTVweDsgLyogUGFkZGluZyBpbnNpZGUgdGhlIGJveCAqLwogIGJvcmRlci1yYWRpdXM6IDVweDsgLyogUm91bmRlZCBjb3JuZXJzICovCiAgbWFyZ2luLWJvdHRvbTogMjBweDsgLyogU3BhY2luZyBiZWxvdyB0aGUgYm94ICovCn0KLmNhcHRpb24gewogIG1hcmdpbjogYXV0bzsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgbWFyZ2luLWJvdHRvbTogMjBweDsgLyogU3BhY2luZyBiZWxvdyB0aGUgYm94ICovCn0KYGBgCgoKTGV0IHVzIHNldCBzb21lIGdsb2JhbCBvcHRpb25zIGZvciBhbGwgY29kZSBjaHVua3MgaW4gdGhpcyBkb2N1bWVudC4KCgpgYGB7cn0KIyBTZXQgc2VlZCBmb3IgcmVwcm9kdWNpYmlsaXR5CnNldC5zZWVkKDE5ODIpIAojIFNldCBnbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAjIERpc2FibGUgbWVzc2FnZXMgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAKICAjIERpc2FibGUgd2FybmluZ3MgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAKICAjIFNob3cgUiBjb2RlIHdpdGhpbiBjb2RlIGNodW5rcyBpbiBvdXRwdXQKICBlY2hvID0gVFJVRSwgICAgICAgIAogICMgSW5jbHVkZSBib3RoIFIgY29kZSBhbmQgaXRzIHJlc3VsdHMgaW4gb3V0cHV0CiAgaW5jbHVkZSA9IFRSVUUsICAgICAKICAjIEV2YWx1YXRlIFIgY29kZSBjaHVua3MKICBldmFsID0gVFJVRSwgICAgICAgCiAgIyBFbmFibGUgY2FjaGluZyBvZiBSIGNvZGUgY2h1bmtzIGZvciBmYXN0ZXIgcmVuZGVyaW5nCiAgY2FjaGUgPSBGQUxTRSwgICAgICAKICAjIEFsaWduIGZpZ3VyZXMgaW4gdGhlIGNlbnRlciBvZiB0aGUgb3V0cHV0CiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgIyBFbmFibGUgcmV0aW5hIGRpc3BsYXkgZm9yIGhpZ2gtcmVzb2x1dGlvbiBmaWd1cmVzCiAgcmV0aW5hID0gMiwKICAjIFNob3cgZXJyb3JzIGluIHRoZSBvdXRwdXQgaW5zdGVhZCBvZiBzdG9wcGluZyByZW5kZXJpbmcKICBlcnJvciA9IFRSVUUsCiAgIyBEbyBub3QgY29sbGFwc2UgY29kZSBhbmQgb3V0cHV0IGludG8gYSBzaW5nbGUgYmxvY2sKICBjb2xsYXBzZSA9IEZBTFNFCikKIyBTdGFydCB0aGUgZmlndXJlIGNvdW50ZXIKZmlnX2NvdW50IDwtIDAKIyBEZWZpbmUgdGhlIGNhcHRpb25lciBmdW5jdGlvbgpjYXB0aW9uZXIgPC0gZnVuY3Rpb24oY2FwdGlvbikgewogIGZpZ19jb3VudCA8PC0gZmlnX2NvdW50ICsgMQogIHBhc3RlMCgiRmlndXJlICIsIGZpZ19jb3VudCwgIjogIiwgY2FwdGlvbikKfQojIERlZmluZSB0aGUgZnVuY3Rpb24gdG8gdHJ1bmNhdGUgYSBudW1iZXIgdG8gdHdvIGRlY2ltYWwgcGxhY2VzCnRydW5jYXRlX3RvX3R3byA8LSBmdW5jdGlvbih4KSB7CiAgZmxvb3IoeCAqIDEwMCkgLyAxMDAKfQpgYGAKCgoKCmBgYHtyfQojIGlubGEudXBncmFkZSh0ZXN0aW5nID0gVFJVRSkKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiaW5sYWJydS1vcmcvaW5sYWJydSIsIHJlZiA9ICJkZXZlbCIpCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImRhdmlkYm9saW4vcnNwZGUiLCByZWYgPSAiZGV2ZWwiKQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJkYXZpZGJvbGluL21ldHJpY2dyYXBoIiwgcmVmID0gImRldmVsIikKbGlicmFyeShJTkxBKQpsaWJyYXJ5KGlubGFicnUpCmxpYnJhcnkoclNQREUpCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoZ3JhdGVmdWwpCgpsaWJyYXJ5KHBsb3RseSkKYGBgCgoKV2Ugd2FudCB0byBzb2x2ZSB0aGUgZnJhY3Rpb25hbCBkaWZmdXNpb24gZXF1YXRpb24KXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6bWFpbmVxfQogICAgXHBhcnRpYWxfdCB1Kyhca2FwcGFeMi1cRGVsdGFfXEdhbW1hKV57XGZyYWN7XGFscGhhfXsyfX0gdT1mIFx0ZXh0IHsgb24gfSBcR2FtbWEgXHRpbWVzKDAsIFQpLCBccXVhZCB1KDApPXVfMCBcdGV4dCB7IG9uIH0gXEdhbW1hLApcZW5ke2VxdWF0aW9ufQp3aGVyZSAkdSQgc2F0aXNmaWVzIHRoZSBLaXJjaGhvZmYgdmVydGV4IGNvbmRpdGlvbnMKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6S2NvbmR9CiAgICBcbGVmdFx7XHBoaVxpbiBDKFxHYW1tYSlcO1xCaWd8XDsgXGZvcmFsbCB2XGluIFY6IFxzdW1fe2VcaW5cbWF0aGNhbHtFfV92fVxwYXJ0aWFsX2UgXHBoaSh2KT0wIFxyaWdodFx9ClxlbmR7ZXF1YXRpb259CgpJZiAkZj0wJCwgdGhlbiB0aGUgc29sdXRpb24gaXMgZ2l2ZW4gYnkKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6c29sX3JlcHJlbnRhdGlvbn0KICAgICAgICB1KHMsdCkgPSBcZGlzcGxheXN0eWxlXHN1bV97alxpblxtYXRoYmJ7Tn19ZV57LVxsYW1iZGFee1xmcmFje1xhbHBoYX17Mn19X2p0fVxsZWZ0KHVfMCwgZV9qXHJpZ2h0KV97TF8yKFxHYW1tYSl9ZV9qKHMpLgpcZW5ke2VxdWF0aW9ufQoKYGBge3J9CiMgRnVuY3Rpb24gdG8gYnVpbGQgYSB0YWRwb2xlIGdyYXBoIGFuZCBjcmVhdGUgYSBtZXNoCmdldHNfZ3JhcGhfdGFkcG9sZSA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwKQogIGVkZ2UyIDwtIGNiaW5kKDErMS9waStjb3ModGhldGEpL3BpLHNpbih0aGV0YSkvcGkpCiAgZWRnZXMgPSBsaXN0KGVkZ2UxLCBlZGdlMikKICBncmFwaCA8LSBtZXRyaWNfZ3JhcGgkbmV3KGVkZ2VzID0gZWRnZXMpCiAgZ3JhcGgkYnVpbGRfbWVzaChoID0gaCkKICByZXR1cm4oZ3JhcGgpCn0KYGBgCgpMZXQgJFxHYW1tYV9UID0gKFxWY2FsLFxFY2FsKSQgY2hhcmFjdGVyaXplIHRoZSB0YWRwb2xlIGdyYXBoIHdpdGggJFxWY2FsID0gXHt2XzEsdl8yXH0kIGFuZCAkXEVjYWwgPSBce2VfMSxlXzJcfSQgYXMgc3BlY2lmaWVkIGluIEZpZ3VyZSBccmVme0ludGVydmFsLkNpcmNsZS5UYWRwb2xlfWMuIFRoZSBsZWZ0IGVkZ2UgJGVfMSQgaGFzIGxlbmd0aCAxIGFuZCB0aGUgY2lyY3VsYXIgZWRnZSAkZV8yJCBoYXMgbGVuZ3RoIDIuIEFzIGRpc2N1c3NlZCBpbiBTdWJzZWN0aW9uIFxyZWZ7c3Vic2VjOnByZWxpbX0sIGEgcG9pbnQgb24gJGVfMSQgaXMgcGFyYW1ldGVyaXplZCB2aWEgJHM9XGxlZnQoZV8xLCB0XHJpZ2h0KSQgZm9yICR0IFxpblswLDFdJCBhbmQgYSBwb2ludCBvbiAkZV8yJCB2aWEgJHM9XGxlZnQoZV8yLCB0XHJpZ2h0KSQgZm9yICR0XGluWzAsMl0kLiBPbmUgY2FuIHZlcmlmeSB0aGF0ICQtXERlbHRhX1xHYW1tYSQgaGFzIGVpZ2VudmFsdWVzICQwLFxsZWZ0XHsoaSBccGkgLyAyKV4yXHJpZ2h0XH1fe2kgXGluIFxtYXRoYmJ7Tn19JCBhbmQgJFxsZWZ0XHsoaSBccGkgLyAyKV4yXHJpZ2h0XH1fezIgaSBcaW4gXG1hdGhiYntOfX0kIHdpdGggY29ycmVzcG9uZGluZyBlaWdlbmZ1bmN0aW9ucyAkXHBoaV8wJCwgJFxsZWZ0XHtccGhpX2lccmlnaHRcfV97aSBcaW4gXG1hdGhiYntOfX0kLCBhbmQgJFxsZWZ0XHtccHNpX2lccmlnaHRcfV97MiBpIFxpbiBcbWF0aGJie059fSQgZ2l2ZW4gYnkgJFxwaGlfMChzKT0xIC8gXHNxcnR7M30kIGFuZCAKXGJlZ2lue2VxdWF0aW9uKn0KICAgIFxwaGlfaShzKT1DX3tccGhpLCBpfVxiZWdpbntjYXNlc30KICAgICAgICAtMiBcc2luIChcZnJhY3tpXHBpfXsyfSkgXGNvcyAoXGZyYWN7aSBccGkgdH17Mn0pLCAmIHMgXGluIGVfMSwgXFwKXHNpbiAoaSBccGkgdCAvIDIpLCAmIHMgXGluIGVfMiwKICAgIFxlbmR7Y2FzZXN9LApccXVhZCAKICAgIFxwc2lfaShzKT1cZnJhY3tcc3FydHszfX17XHNxcnR7Mn19IFxiZWdpbntjYXNlc30KICAgICgtMSlee2kgLyAyfSBcY29zIChcZnJhY3tpIFxwaSB0fXsyfSksICYgcyBcaW4gZV8xLCBcXApcY29zIChcZnJhY3tpIFxwaSB0fXsyfSksICYgcyBcaW4gZV8yLApcZW5ke2Nhc2VzfSwKXGVuZHtlcXVhdGlvbip9CndoZXJlICRDX3tccGhpLCBpfT0xJCBpZiAkaSQgaXMgZXZlbiBhbmQgJENfe1xwaGksIGl9PTEgLyBcc3FydHszfSQgb3RoZXJ3aXNlLiBNb3Jlb3ZlciwgdGhlc2UgZnVuY3Rpb25zIGZvcm0gYW4gb3J0aG9ub3JtYWwgYmFzaXMgZm9yICRMXzIoXEdhbW1hX1QpJC4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIGVpZ2VuZnVuY3Rpb25zIAp0YWRwb2xlLmVpZyA8LSBmdW5jdGlvbihrLGdyYXBoKXsKeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAp4MiA8LSBjKDAsZ3JhcGgkZ2V0X2VkZ2VfbGVuZ3RocygpWzJdKmdyYXBoJG1lc2gkUHRFW2dyYXBoJG1lc2gkUHRFWywxXT09MiwyXSkgCgppZihrPT0wKXsgCiAgZi5lMSA8LSByZXAoMSxsZW5ndGgoeDEpKSAKICBmLmUyIDwtIHJlcCgxLGxlbmd0aCh4MikpIAogIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICBmID0gbGlzdChwaGk9ZjEvc3FydCgzKSkgCiAgCn0gZWxzZSB7CiAgZi5lMSA8LSAtMipzaW4ocGkqayoxLzIpKmNvcyhwaSprKngxLzIpIAogIGYuZTIgPC0gc2luKHBpKmsqeDIvMikgICAgICAgICAgICAgICAgICAKICAKICBmMSA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLCBmLmUyWy0xXSkgCiAgCiAgaWYoKGsgJSUgMik9PTEpeyAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICB9IGVsc2UgeyAKICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgZi5lMiA8LSBjb3MocGkqayp4Mi8yKQogICAgZjIgPSBjKGYuZTFbMV0sZi5lMlsxXSxmLmUxWy0xXSxmLmUyWy0xXSkgCiAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgfQp9CgpyZXR1cm4oZikKfQpgYGAKCkltcGxlbWVudGF0aW9uIG9mICR1JAoKYGBge3J9CmggPC0gMC4wMDEKZ3JhcGggPC0gZ2V0c19ncmFwaF90YWRwb2xlKGggPSBoKQpUX2ZpbmFsIDwtIDAuNQp0aW1lX3N0ZXAgPC0gMC4wMQp0aW1lX3NlcSA8LSBzZXEoMCwgVF9maW5hbCwgYnkgPSB0aW1lX3N0ZXApCiMgQ29tcHV0ZSB0aGUgRkVNIG1hdHJpY2VzCmdyYXBoJGNvbXB1dGVfZmVtKCkKRyA8LSBncmFwaCRtZXNoJEcKQyA8LSBncmFwaCRtZXNoJEMKSSA8LSBNYXRyaXg6OkRpYWdvbmFsKG5yb3coQykpCnggPC0gZ3JhcGgkbWVzaCRWWywgMV0KeSA8LSBncmFwaCRtZXNoJFZbLCAyXQplZGdlX251bWJlciA8LSBncmFwaCRtZXNoJFZ0RVssIDFdCnBvcyA8LSBzdW0oZWRnZV9udW1iZXIgPT0gMSkrMQpvcmRlcl90b19wbG90IDwtIGZ1bmN0aW9uKHYpcmV0dXJuKGModlsxXSwgdlszOnBvc10sIHZbMl0sIHZbKHBvcysxKTpsZW5ndGgodildLCB2WzJdKSkKd2VpZ2h0cyA8LSBncmFwaCRtZXNoJHdlaWdodHMKIyBJbml0aWFsIGNvbmRpdGlvbgpVXzAgPC0gMTAqZXhwKC0oKHgtMSleMiArICh5KV4yKSkKClVfdHJ1ZSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KEMpLCBuY29sID0gbGVuZ3RoKHRpbWVfc2VxKSkKVV90cnVlWywgMV0gPC0gVV8wCmBgYAoKCmBgYHtyfQprYXBwYSA8LSAxCmFscGhhIDwtIDEuMwpiZXRhIDwtIGFscGhhLzIKTCA8LSBrYXBwYV4yKkMgKyBHCm9wIDwtIGZyYWN0aW9uYWwub3BlcmF0b3JzKEwsIGJldGEsIEMsIHNjYWxlLmZhY3RvciA9IGthcHBhXjIsIG0gPSAyKQpQbCA8LSBvcCRQbApQciA8LSBvcCRQcgpDaSA8LSBvcCRDaQpgYGAKCgpgYGB7cn0Kbl9maW5pdGUgPC0gMTAwCgoKZm9yIChrIGluIDE6KGxlbmd0aCh0aW1lX3NlcSkgLSAxKSkgewogIGF1eF9rIDwtIHJlcCgwLCBucm93KEMpKQogIGZvciAoaiBpbiAwOm5fZmluaXRlKSB7CiAgICBkZWNheV9qIDwtIGV4cCgtdGltZV9zZXFbaysxXSooa2FwcGFeMiArIChqKnBpLzIpXjIpXihhbHBoYS8yKSkKICAgIGVfaiA8LSB0YWRwb2xlLmVpZyhqLGdyYXBoKSRwaGkKICAgIGF1eF9rIDwtIGF1eF9rICsgZGVjYXlfaipzdW0oVV8wKmVfaip3ZWlnaHRzKSplX2oKICAgIGlmIChqPjAgJiYgKGogJSUgMiA9PSAwKSkgewogICAgICBlX2ogPC0gdGFkcG9sZS5laWcoaixncmFwaCkkcHNpCiAgICAgIGF1eF9rIDwtIGF1eF9rICsgZGVjYXlfaipzdW0oVV8wKmVfaip3ZWlnaHRzKSplX2oKICAgICAgfQogICAgfQogIFVfdHJ1ZVssIGsgKyAxXSA8LSBhdXhfawp9CmBgYAoKYGBge3J9CiMgUHJlY29tcHV0ZSB0aGUgTEhTMSBtYXRyaXgKTEhTMSA8LSBQciArIHRpbWVfc3RlcCAqIHNvbHZlKEMsIFBsKQojIFByZWNvbXB1dGUgdGhlIExIUzIgbWF0cml4CmF1eCA8LSBQciAlKiUgc29sdmUoUGwsIEMpCkxIUzIgPC0gYXV4ICsgdGltZV9zdGVwICogTWF0cml4OjpEaWFnb25hbChucm93KEMpKSAKCgoKIyBJbml0aWFsaXplIFUgbWF0cml4IHRvIHN0b3JlIHNvbHV0aW9uIGF0IGVhY2ggdGltZSBzdGVwClVfYXBwcm94MSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KEMpLCBuY29sID0gbGVuZ3RoKHRpbWVfc2VxKSkKVV9hcHByb3gxWywgMV0gPC0gVV8wCgpVX2FwcHJveDIgPC0gbWF0cml4KE5BLCBucm93ID0gbnJvdyhDKSwgbmNvbCA9IGxlbmd0aCh0aW1lX3NlcSkpClVfYXBwcm94MlssIDFdIDwtIFVfMAoKIyBUaW1lLXN0ZXBwaW5nIGxvb3AKZm9yIChrIGluIDE6KGxlbmd0aCh0aW1lX3NlcSkgLSAxKSkgewogICMgQ29tcHV0ZSB0aGUgcmlnaHQtaGFuZCBzaWRlIGZvciB0aGUgZmlyc3QgZXF1YXRpb24KICBSSFMxIDwtIFByICUqJSBVX2FwcHJveDFbLCBrXQogIFVfYXBwcm94MVssIGsgKyAxXSA8LSBhcy5tYXRyaXgoc29sdmUoTEhTMSwgUkhTMSkpCiAgIyBDb21wdXRlIHRoZSByaWdodC1oYW5kIHNpZGUgZm9yIHRoZSBzZWNvbmQgZXF1YXRpb24KICBSSFMyIDwtIGF1eCAlKiUgVV9hcHByb3gyWywga10KICBVX2FwcHJveDJbLCBrICsgMV0gPC0gYXMubWF0cml4KHNvbHZlKExIUzIsIFJIUzIpKQp9CmBgYAoKCgpgYGB7cn0KeCA8LSBvcmRlcl90b19wbG90KHgpCnkgPC0gb3JkZXJfdG9fcGxvdCh5KQptYXhfZXJyb3JfYXRfZWFjaF90aW1lMSA8LSBhcHBseShhYnMoVV90cnVlIC0gVV9hcHByb3gxKSwgMiwgbWF4KQptYXhfZXJyb3JfYXRfZWFjaF90aW1lMiA8LSBhcHBseShhYnMoVV90cnVlIC0gVV9hcHByb3gyKSwgMiwgbWF4KQptYXhfZXJyb3JfYmV0d2Vlbl9ib3RoX2FwcHJveCA8LSBhcHBseShhYnMoVV9hcHByb3gxIC0gVV9hcHByb3gyKSwgMiwgbWF4KQoKVV90cnVlIDwtIGFwcGx5KFVfdHJ1ZSwgMiwgb3JkZXJfdG9fcGxvdCkKVV9hcHByb3gxIDwtIGFwcGx5KFVfYXBwcm94MSwgMiwgb3JkZXJfdG9fcGxvdCkKVV9hcHByb3gyIDwtIGFwcGx5KFVfYXBwcm94MiwgMiwgb3JkZXJfdG9fcGxvdCkKCiMgQ3JlYXRlIGludGVyYWN0aXZlIHBsb3QKZmlnIDwtIHBsb3RfbHkoKQoKIyBBZGQgZmlyc3QgbGluZSAobWF4X2Vycm9yX2F0X2VhY2hfdGltZTEpCmZpZyA8LSBmaWcgJT4lIGFkZF90cmFjZSgKICB4ID0gfnRpbWVfc2VxLCB5ID0gfm1heF9lcnJvcl9hdF9lYWNoX3RpbWUxLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLAogIGxpbmUgPSBsaXN0KGNvbG9yID0gJ3JlZCcsIHdpZHRoID0gMiksCiAgbWFya2VyID0gbGlzdChzaXplID0gNCksCiAgbmFtZSA9ICJNYXggRXJyb3IgQmV0d2VlbiBUcnVlIGFuZCBBcHByb3ggMTogKFBfciArdGF1IENeey0xfVBfbClVXntrKzF9ID0gUF9yIFVee2t9IgopCgojIEFkZCBzZWNvbmQgbGluZSAobWF4X2Vycm9yX2F0X2VhY2hfdGltZTIpCmZpZyA8LSBmaWcgJT4lIGFkZF90cmFjZSgKICB4ID0gfnRpbWVfc2VxLCB5ID0gfm1heF9lcnJvcl9hdF9lYWNoX3RpbWUyLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLAogIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsdWUnLCB3aWR0aCA9IDIsIGRhc2ggPSAnZGFzaCcpLAogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDQpLAogIG5hbWUgPSAiTWF4IEVycm9yIEJldHdlZW4gVHJ1ZSBhbmQgQXBwcm94IDI6IChQX3JQX2xeey0xfUMgK3RhdSBJKVVee2srMX0gPSBQX3JQX2xeey0xfUMgVV57a30iCikKCiMgQWRkIHRoaXJkIGxpbmUgKG1heF9lcnJvcl9iZXR3ZWVuX2JvdGhfYXBwcm94KQoKZmlnIDwtIGZpZyAlPiUgYWRkX3RyYWNlKAogIHggPSB+dGltZV9zZXEsIHkgPSB+bWF4X2Vycm9yX2JldHdlZW5fYm90aF9hcHByb3gsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrbWFya2VycycsCiAgbGluZSA9IGxpc3QoY29sb3IgPSAnZ3JlZW4nLCB3aWR0aCA9IDIsIGRhc2ggPSAnZG90JyksCiAgbWFya2VyID0gbGlzdChzaXplID0gNCksCiAgbmFtZSA9ICJNYXggRXJyb3IgQmV0d2VlbiBBcHByb3hpbWF0aW9ucyIKKQoKIyBMYXlvdXQKZmlnIDwtIGZpZyAlPiUgbGF5b3V0KAogIHRpdGxlID0gIk1heCBFcnJvciBhdCBFYWNoIFRpbWUgU3RlcCIsCiAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlRpbWUiKSwKICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTWF4IEVycm9yIiksCiAgbGVnZW5kID0gbGlzdCh4ID0gMC4xLCB5ID0gMC45KQopCgoKcGxvdF9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgeCA9IHJlcCh4LCB0aW1lcyA9IG5jb2woVV90cnVlKSksCiAgeSA9IHJlcCh5LCB0aW1lcyA9IG5jb2woVV90cnVlKSksCiAgel90cnVlID0gYXMudmVjdG9yKFVfdHJ1ZSksCiAgel9hcHByb3gxID0gYXMudmVjdG9yKFVfYXBwcm94MSksCiAgel9hcHByb3gyID0gYXMudmVjdG9yKFVfYXBwcm94MiksCiAgZnJhbWUgPSByZXAodGltZV9zZXEsIGVhY2ggPSBsZW5ndGgoeCkpCikKCiMgQ29tcHV0ZSBheGlzIGxpbWl0cwp4X3JhbmdlIDwtIHJhbmdlKHgpCnlfcmFuZ2UgPC0gcmFuZ2UoeSkKel9yYW5nZSA8LSByYW5nZShjKFVfdHJ1ZSwgVV9hcHByb3gxLCBVX2FwcHJveDIpKQoKIyBJbml0aWFsIHBsb3Qgc2V0dXAgKGZpcnN0IGZyYW1lIG9ubHkpCnAgPC0gcGxvdF9seShwbG90X2RhdGEsIGZyYW1lID0gfmZyYW1lKSAlPiUKICBhZGRfdHJhY2UoCiAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56X3RydWUsCiAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgbmFtZSA9ICJUcnVlIiwKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsdWUiLCB3aWR0aCA9IDIpCiAgKSAlPiUKICBhZGRfdHJhY2UoCiAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56X2FwcHJveDEsCiAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgbmFtZSA9ICJBcHByb3ggMTogKFBfciArdGF1IENeey0xfVBfbClVXntrKzF9ID0gUF9yIFVee2t9IiwKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIHdpZHRoID0gMikKICApICU+JQogIGFkZF90cmFjZSgKICAgIHggPSB+eCwgeSA9IH55LCB6ID0gfnpfYXBwcm94MiwKICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICBuYW1lID0gIkFwcHJveCAyOiAoUF9yUF9sXnstMX1DICt0YXUgSSlVXntrKzF9ID0gUF9yUF9sXnstMX1DIFVee2t9IiwKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImdyZWVuIiwgd2lkdGggPSAyKQogICkgJT4lCiAgbGF5b3V0KAogICAgc2NlbmUgPSBsaXN0KAogICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAieCIsIHJhbmdlID0geF9yYW5nZSksCiAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJ5IiwgcmFuZ2UgPSB5X3JhbmdlKSwKICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gIlZhbHVlIiwgcmFuZ2UgPSB6X3JhbmdlKQogICAgKSwKICAgIHVwZGF0ZW1lbnVzID0gbGlzdCgKICAgICAgbGlzdCgKICAgICAgICB0eXBlID0gImJ1dHRvbnMiLCBzaG93YWN0aXZlID0gRkFMU0UsCiAgICAgICAgYnV0dG9ucyA9IGxpc3QoCiAgICAgICAgICBsaXN0KGxhYmVsID0gIlBsYXkiLCBtZXRob2QgPSAiYW5pbWF0ZSIsCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KE5VTEwsIGxpc3QoZnJhbWUgPSBsaXN0KGR1cmF0aW9uID0gMTAwLCByZWRyYXcgPSBUUlVFKSwgZnJvbWN1cnJlbnQgPSBUUlVFKSkpLAogICAgICAgICAgbGlzdChsYWJlbCA9ICJQYXVzZSIsIG1ldGhvZCA9ICJhbmltYXRlIiwKICAgICAgICAgICAgICAgYXJncyA9IGxpc3QoTlVMTCwgbGlzdChtb2RlID0gImltbWVkaWF0ZSIsIGZyYW1lID0gbGlzdChkdXJhdGlvbiA9IDApLCByZWRyYXcgPSBGQUxTRSkpKQogICAgICAgICkKICAgICAgKQogICAgKSwKICAgIHRpdGxlID0gIlRpbWU6IDAiCiAgKQoKIyBDb252ZXJ0IHRvIHBsb3RseSBvYmplY3Qgd2l0aCBmcmFtZSBpbmZvCnBiIDwtIHBsb3RseV9idWlsZChwKQoKIyBJbmplY3QgY3VzdG9tIHRpdGxlcyBpbnRvIGVhY2ggZnJhbWUKZm9yIChpIGluIHNlcV9hbG9uZyhwYiR4JGZyYW1lcykpIHsKICB0IDwtIHRpbWVfc2VxW2ldCiAgZXJyIDwtIHNpZ25pZihtYXhfZXJyb3JfYmV0d2Vlbl9ib3RoX2FwcHJveFtpXSwgNCkKICBwYiR4JGZyYW1lc1tbaV1dJGxheW91dCA8LSBsaXN0KHRpdGxlID0gcGFzdGUwKCJUaW1lOiAiLCB0LCAiIHwgTWF4IEVycm9yOiAiLCBlcnIpKQp9CmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgb3V0LndpZHRoID0gIjUwJSIsIGZpZy5jYXAgPSBjYXB0aW9uZXIoIkNhcHRpb24iKX0KZmlnICAjIERpc3BsYXkgdGhlIHBsb3QKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBvdXQud2lkdGggPSAiMTAwJSIsIGZpZy5jYXAgPSBjYXB0aW9uZXIoIkNhcHRpb24iKX0KcGIKYGBgCgo=